package simmar.neat;


import simmar.utilities.IO;
import ch.idsia.agents.*;
import ch.idsia.benchmark.tasks.BasicTask;
import ch.idsia.benchmark.tasks.MarioCustomSystemOfValues;
import ch.idsia.benchmark.tasks.SystemOfValues;
import ch.idsia.tools.MarioAIOptions;
import com.anji.integration.Activator;

public class NEATGameWrapper {
	
	private static MarioAIOptions marioAIOptions;
	private static BasicTask basicTask;
	private static MarioCustomSystemOfValues m;
	
	private static boolean initialized = false;
	
	/**
	 * Sets up the game in a static context
	 */
	public static void initGameWrapper(boolean bVisualize) {
		// Init the game for learning
		marioAIOptions = new MarioAIOptions();
		marioAIOptions.setVisualization(bVisualize);
		
		basicTask = new BasicTask(marioAIOptions);
		m = new MarioCustomSystemOfValues();
		
		initialized = true;
	}
	
	/**
	 * @return true if the wrapper is initialized
	 */
	public static boolean isInitialized() {
		return initialized;
	}
	
	/**
	 * evaluates an activator
	 * @param activator the activator to use
	 * @param trials the number of trials to run for the activator
	 * @return fitness value as calculated by mario
	 */
	public static int evaluateActivator (Activator activator, int[] seeds, boolean experiment) {
		if (marioAIOptions != null && basicTask != null && m != null) {
			// Set the activator to use for this trial
			Agent newAgent = new NEATAgent(activator);
			marioAIOptions.setAgent(newAgent);
			basicTask.setOptionsAndReset(marioAIOptions);
			
			int[] difficulty = {0, 1};
			
			int totalfitness = 0;
			
			// Check whether we should run experiment
			if (experiment) {
				int[] altSeeds = IO.LoadObject("seeds");
				int index = 0;
				
				// Set up system of values
				SystemOfValues sov = new SystemOfValues();
				
				sov.coins = 0;
				sov.distance = 2;
				sov.flowerFire = 0;
				sov.greenMushroom = 0;
				sov.hiddenBlock = 0;
				sov.killedByFire = 4;
				sov.killedByShell = 0;
				sov.killedByStomp = 1;
				sov.kills = 2;
				sov.mode = 32;
				sov.mushroom = 0;
				sov.stomp = 0;
				sov.timeLeft = 4;
				sov.win = 512;
				
				// Run first half on difficulty 0
				while (index < (altSeeds.length/2) ) {
					// Set the seed
					marioAIOptions.setLevelRandSeed(altSeeds[index]);
					// Set difficulty
					marioAIOptions.setLevelDifficulty(0);
					basicTask.setOptionsAndReset(marioAIOptions);
					
					// Run episode and print fitness
					basicTask.runSingleEpisode(1);
					System.out.println( (index+1) + " " + basicTask.getEnvironment().getEvaluationInfo().computeWeightedFitness(sov) );
					
					index++;
				}
				
				// Run second half on difficulty 1
				while (index < altSeeds.length ) {
					// Set the seed
					marioAIOptions.setLevelRandSeed(altSeeds[index]);
					// Set difficulty
					marioAIOptions.setLevelDifficulty(1);
					basicTask.setOptionsAndReset(marioAIOptions);
					
					// Run episode and print fitness
					basicTask.runSingleEpisode(1);
					System.out.println( (index+1) + " " + basicTask.getEnvironment().getEvaluationInfo().computeWeightedFitness(sov) );
					
					index++;
				}
				
				
			} else {
				if (seeds != null) {
					for (int i = 0; i<seeds.length; i++) {
						// Set the seed
						marioAIOptions.setLevelRandSeed(seeds[i]);
						
						// Run a game once on each difficulty
						for (int j = 0; j < difficulty.length; j++) {
							// Set difficulty
							marioAIOptions.setLevelDifficulty(difficulty[j]);
							basicTask.setOptionsAndReset(marioAIOptions);
							
							// Run the level
							basicTask.runSingleEpisode(1);
							totalfitness = totalfitness + basicTask.getEnvironment().getEvaluationInfo().computeWeightedFitness(m);
						}
					}
				} else {
					// Run a game once on each difficulty
					for (int j = 0; j < difficulty.length; j++) {
						// Set difficulty
						marioAIOptions.setLevelDifficulty(difficulty[j]);
						basicTask.setOptionsAndReset(marioAIOptions);
						
						// Run the level
						basicTask.runSingleEpisode(1);
						//totalfitness = totalfitness + basicTask.getEnvironment().getEvaluationInfo().computeWeightedFitness(m);
					}
				}
			}
			
			// Return average fitness of the games
			totalfitness = (int) (totalfitness / (seeds.length * difficulty.length));
			return totalfitness;
		}
		
		System.out.println("NEATGameWrapper: Not initialized!");
		return 1;
	}
	
	/**
	 * Remove the game context within the wrapper
	 */
	public static void clear() {
		marioAIOptions = null;
		basicTask = null;
		m = null;
		initialized = false;
	}

}